#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
@FileName: secant.py
@Version: 1.0
@Date: 2023/6/20 10:53
@Description: 割线方法求函数零点
"""

import math
from root_paras import Paras


def secant(fun, paras: Paras = Paras()) -> tuple[float, float, float]:
    sec_tol = paras.sec_tol
    a: float = paras.start
    b: float = paras.end

    if math.fabs(b - a) < sec_tol:
        b = a + paras.dft_sect

    n: int = 0
    sol_tol = paras.sol_tol
    loops = paras.loops
    while math.fabs(b - a) > sec_tol:
        if math.fabs(fun(b) - 0) <= sol_tol:
            break

        n += 1
        if n > loops:
            raise RuntimeError(f'Secant iteration: loop over {loops} times, with interval {b - a}')

        dy: float = fun(b) - fun(a)
        if math.fabs(dy) < sol_tol:
            print(f'Secant method, dy = {dy} ~> 0')

        a, b = b, (a * fun(b) - b * fun(a)) / dy

    if math.fabs((val := fun(b)) - 0) <= sol_tol:
        print(n)
        return b, a, b
    else:
        raise RuntimeError(f'Secant iteration: did not converge to zero, instead -> {val}')


if __name__ == '__main__':
    f = lambda x: x ** 3 + x - 1
    res = secant(f)
    print(res)
